package com.chongqing.shiro.config;


import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.chongqing.shiro.service.filter.FilterChainDefinitions;
import com.chongqing.shiro.service.filter.MyShiroRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description: shiro配置类
 * -------------------
 * @Author: YangXingfu
 * @Date: 2019/01/04 17:19
 * */



@Configuration
public class ShiroConfig {

    @Autowired
    private FilterChainDefinitions filterChainDefinitions;

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${spring.redis.password}")
    private String password;


    @Bean
    public static LifecycleBeanPostProcessor getLifeclePostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

     /**
     * @Description:  thymeleaf里使用shiro的bean
     * @Param:
     * @return:  at.pollux.thymeleaf.shiro.dialect.ShiroDialect
     * --------------------
     * @Author:  YangXingfu
     * @Date:  2019/01/04 17:24
      **/


    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

     /**
     * ShiroFilterFactoryBean 处理拦截资源文件
     * 注意：单独一个ShiroFilterFactoryBean配置是或者报错的,因为在
     * 初始化ShiroFilterFactoryBean的时候需要注入SecurityManager
     *
     * Filter Chain定义说明
     * 1.一个URL可以配置多个filter,使用逗号分隔
     * 2.当设置多个过滤器时，全部验证通过，才视为通过
     * 3.部分过滤器可以指定参数, 如perms, roles
     * @param securityManager
     * @return
     */


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //登录url
        shiroFilterFactoryBean.setLoginUrl("/login");
        //登录成功后跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权的界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
        //自定义连接器
        Map<String, Filter> filterMap = new LinkedHashMap<String, Filter>();
        //限制统一账号在线人数（未做）
        //拦截器
        Map<String, String> filterChainDefinitionMap = filterChainDefinitions.loadFilterChainDefinitionos();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    @Bean(name = "securityManager")
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm
        securityManager.setRealm(myShiroRealm());
        // 记住我
        securityManager.setRememberMeManager(rememberMeManager());
        // 自定义session管理,使用redis
        securityManager.setSessionManager(sessionManager());
        // 自定义catch,使用redis
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }

    @Bean
    public RedisCacheManager redisCacheManager() {

        RedisCacheManager redisManager = new RedisCacheManager();
        redisManager.setRedisManager(redisManager());
        return redisManager;
    }

    /**
     * shiro session管理对象
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * RedisSessionDao的实现，使用shiro-redis开源插件
     * 鉴权信息，如果设置了RedisSessionDao，则从redis数据库获取鉴权信息，否则从数据库中读取鉴权信息
     * @return
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }



    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setTimeout(timeout);
        //配置redis缓存过期时间
        redisManager.setExpire(30 * 24 * 60 * 60);
        redisManager.setPassword(password);
        return redisManager;
    }

    /**
     * cookie管理对象
     * @return
     */
    @Bean
    public RememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }


    /**
     * cookie对象
     * @return
     */
    @Bean
    public Cookie rememberMeCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        /*设置cookie有效期为30天*/
        simpleCookie.setMaxAge(60 * 60 * 24 * 30);
        return simpleCookie;
    }

    /**
     * 认证、鉴权对象
     * @return
     */
    @Bean
    public Realm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(hashCredentialsMatcher());
        return myShiroRealm;
    }

    /**
     * 凭证管理器
     * @return
     */
    @Bean
    public CredentialsMatcher hashCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }

}
